From 9cc9df71821d73fb8a1d96819b8d9d7cf10e4993 Mon Sep 17 00:00:00 2001 From: "awilliam@xenbuild.aw" Date: Fri, 21 Apr 2006 10:40:17 -0600 Subject: [PATCH] [IA64] SMP-guest Final SMP-guest patch: add IPI and boot rendez-vous support. Signed-off-by: Tristan Gingold --- .../arch/ia64/kernel/irq_ia64.c | 8 +++ .../arch/ia64/xen/hypercall.S | 10 +++ xen/arch/ia64/xen/dom_fw.c | 46 ++++++++++++-- xen/arch/ia64/xen/hypercall.c | 62 +++++++++++++++++++ xen/include/asm-ia64/dom_fw.h | 5 ++ 5 files changed, 126 insertions(+), 5 deletions(-) diff --git a/linux-2.6-xen-sparse/arch/ia64/kernel/irq_ia64.c b/linux-2.6-xen-sparse/arch/ia64/kernel/irq_ia64.c index 647b0ca608..4f72108eb4 100644 --- a/linux-2.6-xen-sparse/arch/ia64/kernel/irq_ia64.c +++ b/linux-2.6-xen-sparse/arch/ia64/kernel/irq_ia64.c @@ -265,6 +265,14 @@ ia64_send_ipi (int cpu, int vector, int delivery_mode, int redirect) unsigned long ipi_data; unsigned long phys_cpu_id; +#ifdef CONFIG_XEN + if (running_on_xen) { + extern void xen_send_ipi (int cpu, int vec); + xen_send_ipi (cpu, vector); + return; + } +#endif /* CONFIG_XEN */ + #ifdef CONFIG_SMP phys_cpu_id = cpu_physical_id(cpu); #else diff --git a/linux-2.6-xen-sparse/arch/ia64/xen/hypercall.S b/linux-2.6-xen-sparse/arch/ia64/xen/hypercall.S index 2adcd3ed56..a1be624556 100644 --- a/linux-2.6-xen-sparse/arch/ia64/xen/hypercall.S +++ b/linux-2.6-xen-sparse/arch/ia64/xen/hypercall.S @@ -341,3 +341,13 @@ GLOBAL_ENTRY(xen_set_eflag) br.ret.sptk.many rp END(xen_set_eflag) #endif + +GLOBAL_ENTRY(xen_send_ipi) + mov r14=r32 + mov r15=r33 + mov r2=0x380 + break 0x1000 + ;; + br.ret.sptk.many rp + ;; +END(xen_send_ipi) diff --git a/xen/arch/ia64/xen/dom_fw.c b/xen/arch/ia64/xen/dom_fw.c index 9f45769510..36894c12de 100644 --- a/xen/arch/ia64/xen/dom_fw.c +++ b/xen/arch/ia64/xen/dom_fw.c @@ -94,9 +94,24 @@ unsigned long dom_fw_setup(struct domain *d, const char *args, int arglen) /* the following heavily leveraged from linux/arch/ia64/hp/sim/fw-emu.c */ -#define NUM_EFI_SYS_TABLES 6 -# define NUM_MEM_DESCS 5 +/* Set IP and GR1 of not yet initialized vcpu. */ +static void +set_os_boot_rendez (struct domain *d, unsigned long pc, unsigned long gr1) +{ + struct vcpu *v; + int i; + printf ("set_os_boot_rendez: %lx %lx\n", pc, gr1); + for (i = 1; i < MAX_VIRT_CPUS; i++) { + v = d->vcpu[i]; + if (v != NULL + && !test_bit(_VCPUF_initialised, &v->vcpu_flags)) { + struct pt_regs *regs = vcpu_regs (v); + regs->cr_iip = pc; + regs->r1 = gr1; + } + } +} struct sal_ret_values sal_emulator (long index, unsigned long in1, unsigned long in2, @@ -155,7 +170,18 @@ sal_emulator (long index, unsigned long in1, unsigned long in2, printf("NON-PRIV DOMAIN CALLED SAL_PCI_CONFIG_WRITE\n"); break; case SAL_SET_VECTORS: - printf("*** CALLED SAL_SET_VECTORS. IGNORED...\n"); + if (in1 == SAL_VECTOR_OS_BOOT_RENDEZ) { + if (in4 != 0 || in5 != 0 || in6 != 0 || in7 != 0) { + /* Sanity check: cs_length1 must be 0, + second vector is reserved. */ + status = -2; + } + else + set_os_boot_rendez (current->domain, in2, in3); + } + else + printf("*** CALLED SAL_SET_VECTORS %lu. IGNORED...\n", + in1); break; case SAL_GET_STATE_INFO: /* No more info. */ @@ -618,6 +644,9 @@ dom_fw_fake_acpi(struct domain *d, struct fake_acpi_tables *tables) return; } +#define NUM_EFI_SYS_TABLES 6 +#define NUM_MEM_DESCS 5 + static struct ia64_boot_param * dom_fw_init (struct domain *d, const char *args, int arglen, char *fw_mem, int fw_mem_size) { @@ -625,8 +654,9 @@ dom_fw_init (struct domain *d, const char *args, int arglen, char *fw_mem, int f efi_runtime_services_t *efi_runtime; efi_config_table_t *efi_tables; struct ia64_sal_systab *sal_systab; - efi_memory_desc_t *efi_memmap, *md; struct ia64_sal_desc_entry_point *sal_ed; + struct ia64_sal_desc_ap_wakeup *sal_wakeup; + efi_memory_desc_t *efi_memmap, *md; struct ia64_boot_param *bp; unsigned long *pfn; unsigned char checksum = 0; @@ -662,6 +692,7 @@ dom_fw_init (struct domain *d, const char *args, int arglen, char *fw_mem, int f efi_tables = (void *) cp; cp += NUM_EFI_SYS_TABLES * sizeof(*efi_tables); sal_systab = (void *) cp; cp += sizeof(*sal_systab); sal_ed = (void *) cp; cp += sizeof(*sal_ed); + sal_wakeup = (void *) cp; cp += sizeof(*sal_wakeup); efi_memmap = (void *) cp; cp += NUM_MEM_DESCS*sizeof(*efi_memmap); bp = (void *) cp; cp += sizeof(*bp); pfn = (void *) cp; cp += NFUNCPTRS * 2 * sizeof(pfn); @@ -779,7 +810,7 @@ dom_fw_init (struct domain *d, const char *args, int arglen, char *fw_mem, int f sal_systab->size = sizeof(*sal_systab); sal_systab->sal_rev_minor = 1; sal_systab->sal_rev_major = 0; - sal_systab->entry_count = 1; + sal_systab->entry_count = 2; strcpy((char *)sal_systab->oem_id, "Xen/ia64"); strcpy((char *)sal_systab->product_id, "Xen/ia64"); @@ -792,6 +823,11 @@ dom_fw_init (struct domain *d, const char *args, int arglen, char *fw_mem, int f dom_fw_hypercall_patch (d, sal_ed->sal_proc, FW_HYPERCALL_SAL_CALL, 1); sal_ed->gp = 0; // will be ignored + /* Fill an AP wakeup descriptor. */ + sal_wakeup->type = SAL_DESC_AP_WAKEUP; + sal_wakeup->mechanism = IA64_SAL_AP_EXTERNAL_INT; + sal_wakeup->vector = XEN_SAL_BOOT_RENDEZ_VEC; + for (cp = (char *) sal_systab; cp < (char *) efi_memmap; ++cp) checksum += *cp; diff --git a/xen/arch/ia64/xen/hypercall.c b/xen/arch/ia64/xen/hypercall.c index f0696cdbe7..448112f842 100644 --- a/xen/arch/ia64/xen/hypercall.c +++ b/xen/arch/ia64/xen/hypercall.c @@ -132,6 +132,65 @@ xen_hypercall (struct pt_regs *regs) } +static void +fw_hypercall_ipi (struct pt_regs *regs) +{ + int cpu = regs->r14; + int vector = regs->r15; + struct vcpu *targ; + + if (0 && vector == 254) + printf ("send_ipi from %d to %d vector=%d\n", + current->vcpu_id, cpu, vector); + + if (cpu > MAX_VIRT_CPUS) + return; + + targ = current->domain->vcpu[cpu]; + if (targ == NULL) + return; + + if (vector == XEN_SAL_BOOT_RENDEZ_VEC + && !test_bit(_VCPUF_initialised, &targ->vcpu_flags)) { + struct pt_regs *targ_regs = vcpu_regs (targ); + struct vcpu_guest_context c; + + printf ("arch_boot_vcpu: %p %p\n", + (void *)targ_regs->cr_iip, + (void *)targ_regs->r1); + memset (&c, 0, sizeof (c)); + /* Copy regs. */ + c.regs.cr_iip = targ_regs->cr_iip; + c.regs.r1 = targ_regs->r1; + + /* Copy from vcpu 0. */ + c.vcpu.evtchn_vector = + current->domain->vcpu[0]->vcpu_info->arch.evtchn_vector; + if (arch_set_info_guest (targ, &c) != 0) { + printf ("arch_boot_vcpu: failure\n"); + return; + } + if (test_and_clear_bit(_VCPUF_down, + &targ->vcpu_flags)) { + vcpu_wake(targ); + printf ("arch_boot_vcpu: vcpu %d awaken %016lx!\n", + targ->vcpu_id, targ_regs->cr_iip); + } + else + printf ("arch_boot_vcpu: huu, already awaken!"); + } + else { + int running = test_bit(_VCPUF_running, + &targ->vcpu_flags); + + vcpu_pend_interrupt(targ, vector); + vcpu_unblock(targ); + if (running) + smp_send_event_check_cpu(targ->processor); + } + return; +} + static int fw_hypercall (struct pt_regs *regs) { @@ -232,6 +291,9 @@ fw_hypercall (struct pt_regs *regs) // FIXME: need fixes in efi.h from 2.6.9 regs->r8 = EFI_UNSUPPORTED; break; + case FW_HYPERCALL_IPI: + fw_hypercall_ipi (regs); + break; default: printf("unknown ia64 fw hypercall %lx\n", regs->r2); regs->r8 = do_ni_hypercall(); diff --git a/xen/include/asm-ia64/dom_fw.h b/xen/include/asm-ia64/dom_fw.h index e5189719ac..4b48f31883 100644 --- a/xen/include/asm-ia64/dom_fw.h +++ b/xen/include/asm-ia64/dom_fw.h @@ -125,9 +125,14 @@ extern unsigned long dom_fw_setup(struct domain *, const char *, int); */ #define FW_HYPERCALL_FIRST_ARCH 0x300UL +#define FW_HYPERCALL_IPI 0x380UL + /* Xen/ia64 user hypercalls. Only used for debugging. */ #define FW_HYPERCALL_FIRST_USER 0xff00UL +/* Interrupt vector used for os boot rendez vous. */ +#define XEN_SAL_BOOT_RENDEZ_VEC 0xF3 + extern struct ia64_pal_retval xen_pal_emulator(UINT64, u64, u64, u64); extern struct sal_ret_values sal_emulator (long index, unsigned long in1, unsigned long in2, unsigned long in3, unsigned long in4, unsigned long in5, unsigned long in6, unsigned long in7); extern struct ia64_pal_retval pal_emulator_static (unsigned long); -- 2.30.2